from rest_framework.viewsets import GenericViewSet
from django_filters import FilterSet, filters
from django_filters.rest_framework import DjangoFilterBackend

import datetime
from api.extension.mixins import DigListModelMixin, DigCreateModelMixin
from api.extension.auth import TokenAuthentication
from api import models
from api.serializers import comment


class CommentFilterSet(FilterSet):
    news = filters.NumberFilter(field_name='news', required=True)
    latest_id = filters.DateTimeFilter(field_name='descendant_update_datetime', lookup_expr='lte')

    class Meta:
        model = models.Comment
        fields = ["latest_id", 'news']


class CommentView(DigListModelMixin, DigCreateModelMixin, GenericViewSet):
    filter_backends = [DjangoFilterBackend]
    filterset_class = CommentFilterSet

    authentication_classes = [TokenAuthentication]

    # 获取某条新闻资讯的 根评论（根据后代更新时间排序）
    queryset = models.Comment.objects.filter(depth=0).order_by("-descendant_update_datetime")
    serializer_class = [comment.CreateCommentSerializer]

    def perform_create(self, serializer):
        reply = serializer.validated_data.get('reply')
        # 表示为根评论
        if not reply:
            instance = serializer.save(user=self.request.user)
        else:
            if not reply.root:
                root = reply
            else:
                root = reply.root
            # 创建评论
            instance = serializer.save(user=self.request.user, depth=reply.depth + 1, root=root)
            # 根评论的最新更新时间
            root.descendant_update_datetime = datetime.datetime.now()
            root.save()

        # 同时与评论关联的资讯news 的评论数也要加1
        instance.news.comment_count += 1
        instance.news.save()

    # 如果为增加评论则用不同的序列化器
    def get_serializer_class(self):
        if self.request.method == 'GET':
            return comment.ListCommentSerializer
        return comment.CreateCommentSerializer

    # 如果添加评论则需要登录认证
    def get_authenticators(self):
        if self.request.method == 'POST':
            return super().get_authenticators()
        return []
